package com.example.librarymanagementproject2.service.impl;


import com.example.librarymanagementproject2.Common.exception.GlobalException;
import com.example.librarymanagementproject2.mapper.LoginMapper;
import com.example.librarymanagementproject2.mapper.UserMapper;
import com.example.librarymanagementproject2.model.dto.LoginResult;
import com.example.librarymanagementproject2.model.dto.UserRegisterDTO;
import com.example.librarymanagementproject2.model.entity.User;
import com.example.librarymanagementproject2.model.enums.UserRole;
import com.example.librarymanagementproject2.service.LoginService;
import com.example.librarymanagementproject2.service.enums.LoginEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName LoginServiceImpl
 * @Description TODO
 * @Author Kx
 * @Date 2025/10/10 20:38
 * @Version 1.0
 */
@Slf4j
@Service
public class LoginServiceImpl implements LoginService {
    @Autowired
    private LoginMapper loginMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;
    // 令牌有效期(7天)
    private static final long TOKEN_EXPIRE_TIME = 168 * 60 * 60;
    @Autowired
    private RedisTemplate<String, Object> redisTemplate; // redis缓存对象

    /**
     * @param userRegisterDTO : 存储用户信息和验证码的传输对象
     * @author: kx
     * @date: 2025/9/29 13:56
     * @description: 用户注册
     */
    @Override
    public void addUser(UserRegisterDTO userRegisterDTO) {
        // 判断用户信息是否为空
        if (userRegisterDTO == null || userRegisterDTO.getUser() == null) {
            throw new GlobalException(500, "用户信息不能为空");
        }
        // 判断邮箱是否为空
        if (userRegisterDTO.getUser().getEmail() == null) {
            throw new GlobalException(500, "邮箱不能为空");
        }
        // 判断用户信息是否已注册
        if (userMapper.getUserByUserName(userRegisterDTO.getUser().getUsername()) != null) {
            throw new GlobalException(500, "该账号已注册");
        }
        // 判断邮箱是否已存在
        if (userMapper.existsByEmail(userRegisterDTO.getUser().getEmail()) != null) {
            throw new GlobalException(500, "该邮箱已存在");
        }
        // 判断邮箱是否合法
        if (!userRegisterDTO.getUser().getEmail().matches("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$")) {
            throw new GlobalException(500, "邮箱格式错误");
        }
        // 判断验证码是否过期
        if (redisTemplate.opsForValue().get(LoginEnum.CAPTCHA_PREFIX.value() + userRegisterDTO.getUser().getEmail()) == null) {
            throw new GlobalException(500, "验证码已过期");
        }
        // 判断验证码是否正确
        if (!String.valueOf(redisTemplate.opsForValue().get(LoginEnum.CAPTCHA_PREFIX.value() + userRegisterDTO.getUser().getEmail())).equals(userRegisterDTO.getCaptcha())) {
            throw new GlobalException(500, "验证码错误");
        }
        // 判断密码和重复密码是否一致
        if (!userRegisterDTO.getUser().getPassword().equals(userRegisterDTO.getConfirmPassword())) {
            throw new GlobalException(500, "密码不一致");
        }
        // 设置读者身份
        userRegisterDTO.getUser().setRole(UserRole.READER);
        // 加密密码
        String encode = passwordEncoder.encode(userRegisterDTO.getUser().getPassword());
        // 设置加密后的密码
        userRegisterDTO.getUser().setPassword(encode);

        try {
            // 添加用户信息
            loginMapper.addUser(userRegisterDTO.getUser());
            // 删除验证码
            redisTemplate.delete(LoginEnum.CAPTCHA_PREFIX.value() + userRegisterDTO.getUser().getEmail());
        } catch (Exception e) {
            throw new GlobalException(500, "添加用户信息失败" + e.getMessage());
        }
    }

    /**
     * @author: kx
     * @date: 2025/9/29 15:47
     * @param username : 用户名
     * @param password : 密码
     * @return org.example.model.entity.User
     * @description: 用户登录
     */
    @Override
    public LoginResult login(String username, String password) {
        // 获取账号信息
        User user = loginMapper.login(username);
        // 判断是否有该账号
        if (user == null) {
            throw new GlobalException(401, "用户名或密码错误");
        }
        // 判断密码是否正确
        if (!passwordEncoder.matches(password, user.getPassword())) {
            throw new GlobalException(403, "用户名或密码错误");
        }
        // 判断用户账号状态
        if (user.getStatus() == 0) {
            throw new GlobalException(402, "用户已被禁用");
        } else if (user.getStatus() == 2) {
            throw new GlobalException(401, "用户已注销");
        }

        // 生成令牌
        String token = UUID.randomUUID().toString().replaceAll("-", "");

        // 构建存储在Redis中的用户对象
        HashMap<String, Object> userMap = new HashMap<>();
        userMap.put("id", user.getId());
        userMap.put("username", user.getUsername());
        userMap.put("realName", user.getRealName());
        userMap.put("email", user.getEmail());
        userMap.put("role", user.getRole().name());

        // 缓存令牌
        redisTemplate.opsForValue().set(LoginEnum.TOKEN_KEY.value() + token, userMap, TOKEN_EXPIRE_TIME, TimeUnit.SECONDS);

        // 构建返回结果
        return LoginResult
                .builder()
                .token(token)
                .id(user.getId())
                .username(user.getUsername()).role(user.getRole().name())
                .expireTime(LocalDateTime.now().plusSeconds(TOKEN_EXPIRE_TIME))
                .build();
    }
}
